
#include "message.h"
#include "message_coder.h"

#include <signal.h>
#include <stdio.h>
#include <stdarg.h>
#ifdef WIN32
#include <windows.h>
#define FMTBUF(buf,fmt,...)				_snprintf_s(buf,_countof(buf),_TRUNCATE,fmt,##__VA_ARGS__)
namespace{
	void DbgError(char* smt, char* file, char* func, int line, const char* format, ...)
	{
#define ASSERTBUFSIZE 2048
		const size_t tsize = 1024;
		char buffer[tsize] = { 0 };
		char assertbuf[ASSERTBUFSIZE] = { 0 };

		memset(buffer, 0, tsize);
		memset(assertbuf, 0, ASSERTBUFSIZE*sizeof(char));

		va_list args;
		int ret;
		va_start(args, format);
		const char* pFileShort = strrchr(file, '\\');
		if (pFileShort == 0)
			pFileShort = file;
		else
			pFileShort++;

		ret = FMTBUF(buffer, "%s:%d:%s() ", pFileShort, line, func);


		ret = vsprintf_s(assertbuf, ASSERTBUFSIZE, format, args);
		memmove_s(buffer + ret, tsize - ret, assertbuf, ret);


		va_end(args);


		char call_stacks[1024] = { 0 }; memset(call_stacks, 0, 1024);
		//gStacker.ShowCallstack(call_stacks, 1024, 6);
		//MakeAssertText(assertbuf, ret, ASSERTBUFSIZE, smt, call_stacks, file, line);

		UINT utype = MB_ABORTRETRYIGNORE | MB_ICONHAND | MB_SETFOREGROUND | MB_TASKMODAL;
		utype |= MB_SETFOREGROUND | MB_TOPMOST;
		const char* title = "Microsoft Visual C++ Runtime Library";

		int nCode = MessageBoxA(NULL, assertbuf, title, utype);
		if (nCode == IDABORT){
			raise(SIGABRT);
			_exit(3);
		}
		if (nCode == IDRETRY){
			DebugBreak();
			return;
		}
		if (nCode == IDIGNORE)
		{
			return;
		}
		abort();
	}
#define BASSERT(smt)  (void)( (!!(smt)) || (DbgError(#smt,__FILE__,__FUNCTION__,__LINE__,""), 0) )
}
#else
//extern "C"{ void * __dso_handle = 0 ;}
#endif

namespace qb{
namespace proto{


Message::Message()
{
}

Message::~Message()
{
    Clear() ;
}

bool Message::GetFieldInfo(int index , const char *& name , Type& type) const 
{
    const char * str = map_values_.names(index) ;
    const Variant * var = map_values_.values(index) ;

    if(str == NULL || var == NULL)
        return false ;

    name = str ;
    type = var->Type ;
    return true ;
}

const std::string& Message::GetType() const
{
	
    return header_.GetType();
}

void Message::SetType(const std::string& type)
{
	
    header_.SetType(type);
}

const std::string& Message::GetSubject() const
{
	
    return header_.GetSubject();
}

void Message::SetSubject(const std::string& subject)
{
	
    header_.SetSubject(subject);
}

const std::string& Message::GetMessageID() const
{
	
    return header_.GetMessageID();
}

void Message::SetMessageID(const std::string& id)
{
	
    header_.SetMessageID(id);
}

Message::Message(const Message& msg)
{
    copy(msg) ;
}

Message& Message::operator=(const Message& msg)
{
    copy(msg) ;
    return (*this) ;
}

void Message::copy(const Message& msg) 
{
    header_ = msg.header_;
    map_values_ = msg.map_values_ ;
}

void Message::SetBool(const char *name, bool value)
{
    map_values_.SetBool(name , value) ;
}

void Message::SetUInt8(const char *name, uint8_t value)
{
    map_values_.SetUInt8(name , value) ;
}

void Message::SetUInt16(const char *name, uint16_t value)
{
    map_values_.SetUInt16(name , value) ;
}

void Message::SetUInt32(const char *name, uint32_t value)
{
    map_values_.SetUInt32(name , value) ;
}

void Message::SetUInt64(const char *name, uint64_t value)
{
    map_values_.SetUInt64(name , value) ;
}

void Message::SetInt8(const char *name, int8_t value)
{
    map_values_.SetInt8(name , value) ;
}

void Message::SetInt16(const char *name, int16_t value)
{
    map_values_.SetInt16(name , value) ;
}

void Message::SetInt32(const char *name, int32_t value)
{
    map_values_.SetInt32(name , value) ;
}

void Message::SetInt64(const char *name, int64_t value)
{
    map_values_.SetInt64(name , value) ;
}

void Message::SetFloat(const char *name, float value)
{
    map_values_.SetFloat(name , value) ;
}

void Message::SetDouble(const char *name, double value)
{
    map_values_.SetDouble(name , value) ;
}

void Message::SetString(const char *name, const std::string& value)
{
    map_values_.SetString(name , value) ;
}

void Message::SetRaw(const char *name, const char *value, size_t size)
{
    map_values_.SetRaw(name , value , size) ;
}

void Message::SetMap(const char * name , const Map& map)
{
    map_values_.SetMap(name , map) ;
}

VariantMap* Message::AddMap(const char *name)
{
    return map_values_.AddMap(name) ;
}

VariantList* Message::AddList(const char *name)
{
    return map_values_.AddList(name) ;
}

Variant* Message::AddVariant(const char *name)
{
    return map_values_.AddVariant(name);
}

void Message::SetList(const char * name , const List& list) 
{
    map_values_.SetList(name , list) ;
}

bool Message::GetBool(const char *name, bool &value) const
{
    return map_values_.GetBool(name , value) ;
}

bool Message::GetUInt8(const char *name, uint8_t &value) const
{
    return map_values_.GetUInt8(name , value) ;
}

bool Message::GetUInt16(const char *name, uint16_t &value) const
{
    return map_values_.GetUInt16(name , value) ;
}

bool Message::GetUInt32(const char *name, uint32_t &value) const
{
    return map_values_.GetUInt32(name , value) ;
}

bool Message::GetUInt64(const char *name, uint64_t &value) const
{
    return map_values_.GetUInt64(name , value) ;
}

bool Message::GetInt8(const char *name, int8_t &value) const
{
    return map_values_.GetInt8(name , value) ;
}

bool Message::GetInt16(const char *name, int16_t &value) const
{
    return map_values_.GetInt16(name , value) ;
}

bool Message::GetInt32(const char *name, int32_t &value) const
{
    return map_values_.GetInt32(name , value) ;
}

bool Message::GetInt64(const char *name, int64_t &value) const
{
    return map_values_.GetInt64(name , value) ;
}

bool Message::GetFloat(const char *name, float &value) const
{
    return map_values_.GetFloat(name , value) ;
}

bool Message::GetDouble(const char *name, double &value) const
{
    return map_values_.GetDouble(name , value) ;
}

bool Message::GetString(const char *name, std::string& value) const
{
    return map_values_.GetString(name , value) ;
}

bool Message::GetRaw(const char *name, VariantRaw& value) const
{
    return map_values_.GetRaw(name , value) ;
}

bool Message::GetMap(const char *name, Map&value) const
{
    return map_values_.GetMap(name , value) ;
}

bool Message::GetList(const char * name , List& value) const
{
    return map_values_.GetList(name , value) ;
}


/*
    �ڴ�����ģʽ��������Message����֮ǰ���ͷ����á�
*/
bool Message::RefString(const char *name, const char *& value, size_t &size) const
{
    return map_values_.RefString(name , value , size) ;
}

bool Message::RefRaw(const char *name, const void *& value, size_t &size) const
{
    return map_values_.RefRaw(name , value , size) ;
}

bool Message::RefMap(const char *name, const Map* &value) const
{
    return map_values_.RefMap(name , value) ;
}

bool Message::RefList(const char * name , const List*& value) const
{
    return map_values_.RefList(name , value) ;
}

void Message::Clear()
{
    header_.Clear();
    map_values_.clear() ;
}

int Message::Encode(void * buffer , size_t size) const
{
    Buffer buf(buffer , size) ;
    Encoder encoder(buf);

    Map header ;
	const std::string& type = header_.GetType();
	const std::string& sub = header_.GetSubject();
	const std::string& id = header_.GetMessageID();

    const std::string PropType = "Type.Prop";
    const std::string PropSubject = "Subject.Prop";
    const std::string PropMessageID = "MessageID.Prop" ;

	header.SetString(PropType.c_str(), type);
	header.SetString(PropSubject.c_str(), sub);
	header.SetString(PropMessageID.c_str(), id);

    if(encoder.EncodeMap(header) == false)
        return 0 ;


    if(encoder.EncodeMap(map_values_) == false)
        return 0 ;

    return buf.Offset() ;
}

int Message::EncodeSize() const 
{
    /*
        Ϊ�˱��⸴�ƣ����ǽ�type_ , subject_  , message_id_�����ǽ�������������Ϊһ��map��������ͷ�����൱�����յ�buffer���������2��map
    */
    const std::string PropType = "Type.Prop";
    const std::string PropSubject = "Subject.Prop";
    const std::string PropMessageID = "MessageID.Prop" ;

    Map header ;
    header.SetString(PropType.c_str() , header_.GetType()) ;
    header.SetString(PropSubject.c_str(), header_.GetSubject());
    header.SetString(PropMessageID.c_str(), header_.GetMessageID());

    size_t hsize = Encoder::CalcSizeMap(header) ;
    if(hsize == 0)
        return 0 ;

    size_t dsize =  Encoder::CalcSizeMap(map_values_);
    if(dsize == 0)
        return 0 ;

    return (dsize + hsize) ;
}

int Message::Decode(const void * buffer , size_t size)
{
    int hlen = DecodeHeader(buffer , size) ;
    if(hlen < 0)
        return hlen ;

    int dlen = DecodeBody((const char *)buffer + hlen , size - hlen) ;
    if(dlen < 0)
        return dlen ;

    return (hlen + dlen) ;
}

int Message::DecodeHeader(const void * buffer , size_t size) 
{
    Buffer buf((void *)buffer , size) ;
    Decoder decoder(buf) ;

    header_.Clear();

    Map header ;
    if(decoder.DecodeMapDirect(header) == false)
        return -1 ;

    std::string type , subject , message_id;
    const std::string PropType = "Type.Prop";
    const std::string PropSubject = "Subject.Prop";
    const std::string PropMessageID = "MessageID.Prop" ;

    header.GetString(PropType.c_str(), type);
    header.GetString(PropSubject.c_str(), subject);
    header.GetString(PropMessageID.c_str(), message_id);

    header_.SetType(type);
    header_.SetSubject(subject);
    header_.SetMessageID(message_id);

    return buf.Offset() ;
}

int Message::DecodeBody(const void * buffer , size_t size) 
{
    Buffer buf((void *)buffer , size) ;
    Decoder decoder(buf) ;

    map_values_.clear() ;

    if(decoder.DecodeMapDirect(map_values_) == false)
        return -1 ;

    return buf.Offset() ;
}


void Message::RebuildNameTable()
{
    map_values_.rebuild_name_table() ;
}

}
}
